#include <stdlib.h>
#include "../card_crypto.h"
#include "card_mifare.h"

#define CARD_CRYPTO_LOG(format, ...)    //OSAL_LOG(C_CYAN format C_NONE, ##__VA_ARGS__)
#define __CARD_CRYPTO_LOG(format, ...)  //__OSAL_LOG(C_CYAN format C_NONE, ##__VA_ARGS__)

static void idle_task_process(void)
{
}

/**
  * @brief  生成8字节真随机数
  * @note   
  *         
  * @param  pRandom：随机数缓存区（指向的存储空间必须要有8个字节）
  */
static void CardCrypto_GenerateRandomNumber(uint8_t *pRandom)
{
    Device_Crypto(CALC_RANDOM_NUMBER, NULL, 0, (uint32_t *)&pRandom[0], NULL);
    Device_Crypto(CALC_RANDOM_NUMBER, NULL, 0, (uint32_t *)&pRandom[4], NULL);
}

/**
  * @brief  3DES加解密
  * @note   
  *         
  * @param  dirMode：加密、解密选择 0：加密 1：解密
  * @param  pKey：密钥（指向的存储空间必须要有16个字节）
  * @param  pDst：加解密结果（指向的存储空间必须要有8个字节）
  * @param  pSrc：源数据（指向的存储空间必须要有8个字节）
  */
static void CardCrypto_3DesRun(CryptoMode_enum_t dirMode, uint8_t *pKey, uint8_t *pDst, uint8_t *pSrc)
{
    Crypto_enum_t crypto_mode = (dirMode == MODE_ENCRYPTION) ? TDES_ENCRYPTION : TDES_DECRYPTION;
    Device_Crypto(crypto_mode, pSrc, 8, pDst, pKey);
}

/**
  * @brief  获取3DES-KEY
  * @note   如果KEY全为0，说明KEY未创建，使用硬件随机数创建KEY
  *         
  * @param  pKey：密钥缓存区（指向的存储空间必须要有16个字节）
  *
  * @return SUCCESS/ERROR
  */
static ErrorStatus CardCrypto_GetThreeDesKey(uint8_t *pKey)
{
    uint8_t temp[16], i;

    if (OSAL_NvRead(0, temp, sizeof(temp)) != SUCCESS)
    {
        return ERROR;
    }
    do
    {
        /* 判断3DES-KEY是否创建 */
        for (i = 0; i < sizeof(temp); i++)
        {
            if (temp[i] != 0 && temp[i] != 0xff)
            {
                memcpy(pKey, temp, sizeof(temp));
                return SUCCESS; //已创建
            }
        }

        /* 3DES-KEY未创建，生成真随机数，创建KEY */
        CardCrypto_GenerateRandomNumber(&temp[0]);
        CardCrypto_GenerateRandomNumber(&temp[8]);

        /* 随机数保存到EEPROM */
        if (OSAL_NvWrite(0, temp, sizeof(temp)) != SUCCESS)
        {
            return ERROR;
        }
    } while (1);
}

/**
  * @brief  取随机数
  * @param  len：获取随机数的长度(4/8)
  * @param  rand：随机数
  * @retval 操作状态(SUCCESS or ERROR)
  */
ErrorStatus FMcos_getChallenge(ChallengeNum_Typedef randLen, uint8_t *rand)
{
    uint8_t JO = 0;
    uint16_t status;
    uint16_t swData;
    uint8_t sendBuf[64];
    uint8_t tmp[64];
    uint8_t num;

    memcpy(sendBuf, "\x00\x84\x00\x00", 5);
    sendBuf[4] = randLen;

    status = APDU(&JO, sendBuf, 5, tmp, &num);

    swData = (tmp[num - 2] << 8) | tmp[num - 1];
    if ((status != STATUS_SUCCESS) || (swData != SW_OperateSuccessfully))
    {
        return ERROR;
    }

    memcpy(rand, tmp + 2, randLen);

    return SUCCESS;
}

/**
  * @brief  外部认证
  * @param  keyId：外部认证密钥标识号
  * @param  key：输入的密钥(8/16字节)
  * @param  keyLen：输入的密钥长度
  * @retval 操作状态(SUCCESS or ERROR)
  */
ErrorStatus FMcos_externalAuthenticate(uint8_t keyId, uint8_t *key, uint8_t keyLen)
{
    uint8_t JO = 1;
    uint16_t status;
    uint16_t swData;
    uint8_t sendBuf[64];
    uint8_t tmp[64];
    uint8_t rand[8];
    uint8_t enRand[8];
    uint8_t num;

    /* 取随机数(4/8字节) */
    FMcos_getChallenge(Challenge_8Bytes, rand);

    /* 密钥长度为8，为DES加密 */
    if (keyLen == 8)
    {
        /* DES加密 */
        // des_encrypt(rand, key, enRand);
        // CARD_CRYPTO_LOG("des_encrypt:");
        // for(int i = 0; i < 8; i++)
        // {
        //     CARD_CRYPTO_LOG("%#x ",enRand[i]);
        // }
        // CARD_CRYPTO_LOG("\r\n");
    }
    /* 密码长度为16，为3DES加密 */
    else if (keyLen == 16)
    {
        /* 3DES加密 */
        CardCrypto_3DesRun(MODE_ENCRYPTION, key, enRand, rand);
    }
    /* 密码长度错误，直接返回 */
    else
    {
        CARD_CRYPTO_LOG("key length err\r\n");
        return ERROR;
    }

    memcpy(sendBuf, "\x00\x82\x00\x00\x08", 5);
    sendBuf[3] = keyId;
    memcpy(sendBuf + 5, enRand, 8);

    status = APDU(&JO, sendBuf, 13, tmp, &num);

    swData = (tmp[num - 2] << 8) | tmp[num - 1];
    if ((status != STATUS_SUCCESS) || (swData != SW_OperateSuccessfully))
    {
        return ERROR;
    }
    return SUCCESS;
}

/**
  * @brief  内部认证
  * @param  type：操作类型。0x00：加密计算，0x01：解密计算，0x02：MAC计算
  * @param  keyId：DES密钥标识号
  * @param  data：认证数据
  * @retval 操作状态(SUCCESS or ERROR)
  */
ErrorStatus FMcos_internalAuthenticate(InternalAuthType_Typedef type, uint8_t keyId, uint8_t *data, uint8_t *deData)
{
    uint8_t JO = 1;
    uint16_t status;
    uint16_t swData;
    uint8_t sendBuf[64];
    uint8_t tmp[64];
    uint8_t num;
    uint8_t len;

    memcpy(sendBuf, "\x00\x88", 2);
    sendBuf[2] = type;
    sendBuf[3] = keyId;
    sendBuf[4] = 8;
    memcpy(sendBuf + 5, data, sendBuf[4]);
    len = 5 + sendBuf[4];

    status = APDU(&JO, sendBuf, len, tmp, &num);
    swData = (tmp[num - 2] << 8) | tmp[num - 1];

    swData = (tmp[num - 2] << 8) | tmp[num - 1];
    if ((status != STATUS_SUCCESS) || (swData != SW_OperateSuccessfully))
    {
        return ERROR;
    }
    memcpy(deData, tmp + 2, num - 4);

    return SUCCESS;
}

/**
  * @brief  内部DES加密
  * @param  keyId：DES密钥标识号
  * @param  data：认证数据
  * @retval 操作状态(SUCCESS or ERROR)
  */
ErrorStatus FMcos_internalDesEncrypt(uint8_t keyId, uint8_t *data, uint8_t *deData)
{
    return FMcos_internalAuthenticate(InternalAuth_Encrypt, keyId, data, deData);
}

/**
  * @brief  内部DES解密
  * @param  keyId：DES密钥标识号
  * @param  data：认证数据
  * @retval 操作状态(SUCCESS or ERROR)
  */
ErrorStatus FMcos_internalDesDecrypt(uint8_t keyId, uint8_t *data, uint8_t *deData)
{
    return FMcos_internalAuthenticate(InternalAuth_Decrypt, keyId, data, deData);
}

/**
  * @brief  内部DESMAC
  * @param  keyId：DES密钥标识号
  * @param  data：认证数据
  * @retval 操作状态(SUCCESS or ERROR)
  */
ErrorStatus FMcos_internalDesMac(uint8_t keyId, uint8_t *data, uint8_t *deData)
{
    return FMcos_internalAuthenticate(InternalAuth_MAC, keyId, data, deData);
}

/**
  * @brief  通过文件标识符选择文件
  * @param  fileId：文件标识符
  * @retval 操作状态(SUCCESS or ERROR)
  */
ErrorStatus FMcos_selectById(uint16_t fileId)
{
    uint8_t JO = 1;
    uint16_t status;
    uint16_t swData;
    uint8_t sendBuf[64];
    uint8_t tmp[64];
    uint8_t num;

    memcpy(sendBuf, "\x00\xA4\x00\x00\x02", 5);
    sendBuf[5] = (fileId & 0xff00) >> 8;
    sendBuf[6] = fileId & 0xff;

    CARD_CRYPTO_LOG("FMcos_selectById(7):\r\n");
    status = APDU(&JO, sendBuf, 7, tmp, &num);

    swData = (tmp[num - 2] << 8) | tmp[num - 1];
    if ((status != STATUS_SUCCESS) || (swData != SW_OperateSuccessfully))
    {
        CARD_CRYPTO_LOG("fail\r\n");
        return ERROR;
    }

    return SUCCESS;
}

/**
  * @brief  通过目录名称选择文件
  * @param  fileName：目录文件名称
  * @retval 操作状态(SUCCESS or ERROR)
  */
ErrorStatus FMcos_selectByName(uint8_t *fileName)
{
    uint8_t JO = 1;
    uint16_t status;
    uint16_t swData;
    uint8_t sendBuf[64];
    uint8_t tmp[64];
    uint8_t num;
    uint8_t len;

    memcpy(sendBuf, "\x00\xA4\x04\x00", 4);
    sendBuf[4] = strlen((char *)fileName);
    memcpy(sendBuf + 5, fileName, sendBuf[4]);
    len = 5 + sendBuf[4];

    status = APDU(&JO, sendBuf, len, tmp, &num);

    swData = (tmp[num - 2] << 8) | tmp[num - 1];
    if ((status != STATUS_SUCCESS) || (swData != SW_OperateSuccessfully))
    {
        return ERROR;
    }

    return SUCCESS;
}

/**
  * @brief  擦除目录文件
  * @param  None
  * @retval 操作状态(SUCCESS or ERROR)
  */
ErrorStatus FMcos_eraseDF(void)
{
    uint8_t JO = 0;
    uint16_t status;
    uint16_t swData;
    uint8_t sendBuf[64];
    uint8_t tmp[64];
    uint8_t num;

    CARD_CRYPTO_LOG("FMcos_eraseDF:\r\n");

    memcpy(sendBuf, "\x80\x0E\x00\x00\x00", 5);

    status = APDU(&JO, sendBuf, 5, tmp, &num);

    swData = (tmp[num - 2] << 8) | tmp[num - 1];
    if ((status != STATUS_SUCCESS) || (swData != SW_OperateSuccessfully))
    {
        CARD_CRYPTO_LOG("fail\r\n");
        return ERROR;
    }

    return SUCCESS;
}

/**
  * @brief  创建DF文件
  * @param  fileId：文件标识
  * @param  fileSize：文件空间大小
  * @param  creatPerms：建立权限
  * @param  erasePerms：擦除权限
  * @param  dfName：DF名称
  * @retval 操作状态(SUCCESS or ERROR)
  */
ErrorStatus FMcos_creatDfFile(uint16_t fileId, uint16_t fileSize, uint8_t creatPerms, uint8_t erasePerms, uint8_t *dfName)
{
    uint8_t JO = 1;
    uint16_t status;
    uint16_t swData;
    uint8_t sendBuf[64];
    uint8_t tmp[64];
    uint8_t num;
    uint8_t len;

    CARD_CRYPTO_LOG("FMcos_creatDfFile:\r\n");

    memcpy(sendBuf, "\x80\xE0\xDF\x10\x0D\x38\x04\x00\xF0\xF1\x95\xFF\xFF", 13);
    sendBuf[2] = (fileId & 0xff00) >> 8;
    sendBuf[3] = fileId & 0xff;
    sendBuf[4] = 8 + strlen((char *)dfName);
    sendBuf[6] = (fileSize & 0xff00) >> 8;
    sendBuf[7] = fileSize & 0xff;
    sendBuf[8] = creatPerms;
    sendBuf[9] = erasePerms;
    memcpy(sendBuf + 13, dfName, sendBuf[4] - 8);
    len = 5 + sendBuf[4];

    status = APDU(&JO, sendBuf, len, tmp, &num);

    swData = (tmp[num - 2] << 8) | tmp[num - 1];
    if ((status != STATUS_SUCCESS) || (swData != SW_OperateSuccessfully))
    {
        CARD_CRYPTO_LOG("fail\r\n");
        return ERROR;
    }

    return SUCCESS;
}

/**
  * @brief  创建key文件
  * @param  fileId：文件标识
  * @param  fileSize：文件空间大小
  * @param  shortId：DF文件短标识符
  * @param  addPerms：添加权限
  * @retval 操作状态(SUCCESS or ERROR)
  */
ErrorStatus FMcos_creatKeyFile(uint16_t fileId, uint16_t fileSize, uint8_t shortId, uint8_t addPerms)
{
    uint8_t JO = 1;
    uint16_t status;
    uint16_t swData;
    uint8_t sendBuf[64];
    uint8_t tmp[64];
    uint8_t num;
    uint8_t len;

    CARD_CRYPTO_LOG("FMcos_creatKeyFile:\r\n");

    memcpy(sendBuf, "\x80\xE0\x00\x00\x07\x3F\x00\x80\x01\xF1\xFF\xFF", 12);
    sendBuf[2] = (fileId & 0xff00) >> 8;
    sendBuf[3] = fileId & 0xff;
    sendBuf[4] = 7;
    sendBuf[6] = (fileSize & 0xff00) >> 8;
    sendBuf[7] = fileSize & 0xff;
    sendBuf[8] = shortId;
    sendBuf[9] = addPerms;
    len = 5 + sendBuf[4];

    status = APDU(&JO, sendBuf, len, tmp, &num);

    swData = (tmp[num - 2] << 8) | tmp[num - 1];
    if ((status != STATUS_SUCCESS) || (swData != SW_OperateSuccessfully))
    {
        CARD_CRYPTO_LOG("fail\r\n");
        return ERROR;
    }

    return SUCCESS;
}

/**
  * @brief  创建皆基本文件EF
  * @param  fileType：文件类型()
  * @param  fileId：文件标识
  * @param  fileSize：文件空间大小
  * @param  readPerms：读权限
  * @param  writePerms：写权限
  * @param  securitySettings：
  * @retval 操作状态(SUCCESS or ERROR)
  */
ErrorStatus FMcos_creatEfFile(EFFileType_Typedef fileType, uint16_t fileId, uint16_t fileSize, uint8_t readPerms, uint8_t writePerms, uint8_t securitySettings)
{
    uint8_t JO = 1;
    uint16_t status;
    uint16_t swData;
    uint8_t sendBuf[64];
    uint8_t tmp[64];
    uint8_t num;
    uint8_t len;

    CARD_CRYPTO_LOG("FMcos_creatEfFile:\r\n");

    memcpy(sendBuf, "\x80\xE0\x00\x02\x07\x28\x00\x0F\xF0\xF0\xFF\x80", 12);
    sendBuf[2] = (fileId & 0xff00) >> 8;
    sendBuf[3] = fileId & 0xff;
    sendBuf[4] = 7;
    sendBuf[5] = fileType;
    sendBuf[6] = (fileSize & 0xff00) >> 8;
    sendBuf[7] = fileSize & 0xff;
    sendBuf[8] = readPerms;
    sendBuf[9] = writePerms;
    sendBuf[11] = securitySettings;
    len = 5 + sendBuf[4];

    if (fileType == PBOCFileType)
    {
        sendBuf[6] = 0x02;
        sendBuf[7] = 0x08;
        sendBuf[9] = 0x00;
    }
    else if (fileType == PBOCFileType)
    {
        sendBuf[10] = 0xFF;
        sendBuf[11] = 0xFF;
    }
    status = APDU(&JO, sendBuf, len, tmp, &num);

    swData = (tmp[num - 2] << 8) | tmp[num - 1];
    if ((status != STATUS_SUCCESS) || (swData != SW_OperateSuccessfully))
    {
        CARD_CRYPTO_LOG("fail\r\n");
        return ERROR;
    }

    return SUCCESS;
}

/**
  * @brief  增加或修改密钥
  * @param  keyType：密钥类型
  * @param  keyId：密钥标识
  * @param  usePerms：使用权限
  * @param  updatePerms：更改权限
  * @param  usedStatus：后续状态
  * @param  errCnt：错误计数器
  * @param  key：8/16字节密钥
  * @retval 操作状态(SUCCESS or ERROR)
  */
ErrorStatus FMcos_writeKeyEx(KeyType_TypeDef keyType, uint8_t keyId, uint8_t usePerms, uint8_t updatePerms, uint8_t usedStatus, uint8_t errCnt, uint8_t *key, uint8_t keyLen)
{
    uint8_t JO = 0;
    uint16_t status;
    uint16_t swData;
    uint8_t sendBuf[64];
    uint8_t tmp[64];
    uint8_t num;
    uint8_t len;

    CARD_CRYPTO_LOG("FMcos_writeKey:\r\n");

    memcpy(sendBuf, "\x80\xD4\x01\x00\x0D\x39\xF0\xF1\xFF\x99", 10);
    sendBuf[3] = keyId;
    sendBuf[4] = 5 + keyLen;
    sendBuf[5] = keyType;
    sendBuf[6] = usePerms;
    sendBuf[7] = updatePerms;
    sendBuf[8] = usedStatus;
    sendBuf[9] = errCnt;
    memcpy(sendBuf + 10, key, keyLen);
    len = 5 + sendBuf[4];

    status = APDU(&JO, sendBuf, len, tmp, &num);
    swData = (tmp[num - 2] << 8) | tmp[num - 1];

    if (status != STATUS_SUCCESS)
    {
        CARD_CRYPTO_LOG("fail\r\n");
        return ERROR;
    }
    /* 若返回P1P2参数错误，则有可能密钥已存在，尝试更新该密钥指令 */
    else if (swData == SW_ParamP1P2Err)
    {
        CARD_CRYPTO_LOG("retry:");
        sendBuf[2] = keyType;
        status = APDU(&JO, sendBuf, len, tmp, &num);
        swData = (tmp[num - 2] << 8) | tmp[num - 1];
        if ((status != STATUS_SUCCESS) || (swData != SW_OperateSuccessfully))
        {
            CARD_CRYPTO_LOG("fail\r\n");
            return ERROR;
        }
    }
    return SUCCESS;
}

/**
  * @brief  修改密钥
  * @param  keyType：密钥类型
  * @param  keyId：密钥标识
  * @param  usePerms：使用权限
  * @param  updatePerms：更改权限
  * @param  usedStatus：后续状态
  * @param  errCnt：错误计数器
  * @param  key：8/16字节密钥
  * @retval 操作状态(SUCCESS or ERROR)
  */
ErrorStatus FMcos_updateKeyEx(KeyType_TypeDef keyType, uint8_t keyId, uint8_t usePerms, uint8_t updatePerms, uint8_t usedStatus, uint8_t errCnt, uint8_t *key, uint8_t keyLen)
{
    uint8_t JO = 0;
    uint16_t status;
    uint16_t swData;
    uint8_t sendBuf[64];
    uint8_t tmp[64];
    uint8_t num;
    uint8_t len;

    memcpy(sendBuf, "\x80\xD4\x01\x00\x0D\x39\xF0\xF1\xFF\x99", 10);
    sendBuf[2] = keyType;
    sendBuf[3] = keyId;
    sendBuf[4] = 5 + keyLen;
    sendBuf[5] = keyType;
    sendBuf[6] = usePerms;
    sendBuf[7] = updatePerms;
    sendBuf[8] = usedStatus;
    sendBuf[9] = errCnt;
    memcpy(sendBuf + 10, key, keyLen);
    len = 5 + sendBuf[4];

    status = APDU(&JO, sendBuf, len, tmp, &num);

    swData = (tmp[num - 2] << 8) | tmp[num - 1];
    if ((status != STATUS_SUCCESS) || (swData != SW_OperateSuccessfully))
    {
        return ERROR;
    }
    return SUCCESS;
}

/**
  * @brief  增加或修改密钥
  * @param  keyType：密钥类型
  * @param  keyId：密钥标识
  * @param  key：8/16字节密钥
  * @retval 操作状态(SUCCESS or ERROR)
  */
ErrorStatus FMcos_writeKey(KeyType_TypeDef keyType, uint8_t keyId, uint8_t *key, uint8_t keyLen)
{
    ErrorStatus status;
    switch (keyType)
    {
    case ExternalAuthKeyType:
        status = FMcos_writeKeyEx(ExternalAuthKeyType, keyId, 0xF0, 0xF1, 0xFF, 0x99, key, keyLen);
        break;
    case DesEncryptKeyType:
        status = FMcos_writeKeyEx(DesEncryptKeyType, keyId, 0xF0, 0xF1, 0x01, 0x01, key, keyLen);
        break;
    case DesDecryptKeyType:
        status = FMcos_writeKeyEx(DesDecryptKeyType, keyId, 0xF0, 0xF1, 0x01, 0x01, key, keyLen);
        break;
    case DesMacKeyType:
        status = FMcos_writeKeyEx(DesMacKeyType, keyId, 0xF0, 0xF1, 0x01, 0x01, key, keyLen);
        break;
    case FileLineProtectKeyType:
        status = FMcos_writeKeyEx(FileLineProtectKeyType, keyId, 0xF0, 0xF1, 0xFF, 0x99, key, keyLen);
        break;
    default:
        status = ERROR;
        break;
    }
    return status;
}

/**
  * @brief  修改密钥
  * @param  keyType：密钥类型
  * @param  keyId：密钥标识
  * @param  key：8/16字节密钥
  * @retval 操作状态(SUCCESS or ERROR)
  */
ErrorStatus FMcos_updateKey(KeyType_TypeDef keyType, uint8_t keyId, uint8_t *key, uint8_t keyLen)
{
    ErrorStatus status;
    switch (keyType)
    {
    case ExternalAuthKeyType:
        status = FMcos_updateKeyEx(ExternalAuthKeyType, keyId, 0xF0, 0xF1, 0xFF, 0x99, key, keyLen);
        break;
    case DesEncryptKeyType:
        status = FMcos_updateKeyEx(DesEncryptKeyType, keyId, 0xF0, 0xF1, 0x01, 0x01, key, keyLen);
        break;
    case DesDecryptKeyType:
        status = FMcos_updateKeyEx(DesDecryptKeyType, keyId, 0xF0, 0xF1, 0x01, 0x01, key, keyLen);
        break;
    case DesMacKeyType:
        status = FMcos_updateKeyEx(DesMacKeyType, keyId, 0xF0, 0xF1, 0x01, 0x01, key, keyLen);
        break;
    case FileLineProtectKeyType:
        status = FMcos_updateKeyEx(FileLineProtectKeyType, keyId, 0xF0, 0xF1, 0xFF, 0x99, key, keyLen);
        break;
    default:
        status = ERROR;
        break;
    }
    return status;
}

/**
  * @brief  获取卡片ID
  * @param  pCardId：卡片ID
  * @param  pType：卡片类型（CPU_CARD/M1_CARD）
  * @retval 卡片长度
  */
uint8_t CardCrypto_ReadCardId(uint8_t *pCardId, uint8_t *pType)
{
    uint8_t cardLen = 0, len = 1;
    uint8_t count;
    uint8_t sak;
    uint8_t atq[2];
    uint8_t ats[20];

    *pType = 0;
    if (Request(0x26, atq) == STATUS_SUCCESS)
    {
        __CARD_CRYPTO_LOG("\r\n\r\n");
        CARD_CRYPTO_LOG("Request:%02X %02X", atq[0], atq[1]);
        if (AnticollSelect(pCardId, &cardLen, &sak) == STATUS_SUCCESS)
        {
            /* sak返回0x08为M1卡，返回0x28/0x20为CPU卡 */
            if (sak == 0x08)
            {
                len = cardLen;
                *pType = M1_CARD;
            }
            else if ((sak & 0x20) == 0x20)
            {
                if (RATS(0xE0, 0x51, ats, &count) == STATUS_SUCCESS)
                {
                    len = cardLen;
                    *pType = CPU_CARD;

                    CARD_CRYPTO_LOG("RATS:");
                    for (int i = 0; i < count; i++)
                    {
                        __CARD_CRYPTO_LOG("%02X ", ats[i]);
                    }
                    __CARD_CRYPTO_LOG("\r\n");
                }
                else
                {
                    len = 0;
                }
            }
            __CARD_CRYPTO_LOG("sak=%d\r\n", sak);
        }
    }
    else
    {
        len = 0;
    }

    return len;
}

/**
  * @brief  获取卡片关键密钥
  * @param  pCardId：卡片ID
  * @param  idLen：卡片ID长度
  * @param  pKey：卡片密钥
  * @retval SUCCESS or ERROR
  */
ErrorStatus CardCrypto_GetCardKey(uint8_t *pCardId, uint8_t idLen, uint8_t *pKey)
{
    int i = 0;
    uint8_t parentKey[16];
    uint8_t lData[8], rData[8];
    uint8_t inData[9] = "0000Lock";

    if (idLen == 4)
    {
        memcpy(inData, pCardId, 4);
    }
    else if (idLen == 7)
    {
        memcpy(inData, pCardId, 7);
    }
    else if (idLen == 10)
    {
        memcpy(inData, pCardId, 8);
    }
    else
    {
        return ERROR;
    }

    /* 获取门锁存储的主密钥 */
    CardCrypto_GetThreeDesKey(parentKey);

    /* 密钥分散算法获取子密钥 */
    /* 加密输入文本得到密钥的左半部分密钥 */
    CardCrypto_3DesRun(MODE_ENCRYPTION, parentKey, lData, inData); //加密源数据indata

    /* 加密输入数据取反后的数据得到右半部分密钥 */
    for (i = 0; i < 8; i++)
    {
        inData[i] = ~inData[i];
    }
    CardCrypto_3DesRun(MODE_ENCRYPTION, parentKey, rData, inData); //加密源数据取反后的indata

    memcpy(pKey, lData, 8);
    memcpy(pKey + 8, rData, 8);

    return SUCCESS;
}

/**
  * @brief  验证卡片是否为合法卡片
  * @note   
  *         
  * @param  pCardId：卡片ID
  * @param  idLen：卡片ID长度
  *
  * @return SUCCESS/ERROR
  */
ErrorStatus CardCrypto_VerifyCard(uint8_t *pCardId, uint8_t idLen, uint8_t type, uint8_t *err)
{
    ErrorStatus status;
    uint8_t DESKey[16];
    uint8_t rand[8];
    uint8_t deData1[8];
    uint8_t deData2[8];

    if (type != CPU_CARD) //先验证卡的类型
    {
        *err = CARD_ERR_TYPE;
        CARD_CRYPTO_LOG("Card type error\r\n");
        return ERROR;
    }

    /* 进入目录 */
    idle_task_process();
    status = FMcos_selectByName((uint8_t *)Default_DF_NAME); //通过目录选择文件
    idle_task_process();
    if (status != SUCCESS)
    {
        idle_task_process();
        status = FMcos_selectByName((uint8_t *)Default_DF_NAME); //通过目录选择文件
        if (status != SUCCESS)
        {
            *err = CARD_ERR_UNKNOW;
            CARD_CRYPTO_LOG("Select file failed:\"%s\"\r\n", Default_DF_NAME);
            return ERROR;
        }
    }
    CARD_CRYPTO_LOG("Select file succeed:\"%s\"", Default_DF_NAME);
    *err = CARD_ERR_NO_ADD;

    /* 获取随机数 */
    idle_task_process();
    CardCrypto_GenerateRandomNumber(rand);
    CARD_CRYPTO_LOG("Generate random number succeed");

    // if(FMcos_getChallenge(Challenge_8Bytes, rand) == ERROR)
    // {
    //     return ERROR;
    // }

    /* 内部3DES加密 */
    idle_task_process();
    if (FMcos_internalDesEncrypt(Default_EncKey_Id, rand, deData1) == ERROR) //发送随机数给卡片加密,及得到加密数据
    {
        CARD_CRYPTO_LOG("Cpu card encrypt random number failed\r\n");
        return ERROR;
    }
    CARD_CRYPTO_LOG("Cpu card encrypt random number succeed");

    /* 卡片使命完成，可以关掉天线了 */

    /* 计算des密钥 */
    idle_task_process();
    status = CardCrypto_GetCardKey(pCardId, idLen, DESKey);
    if (status == ERROR)
    {
        return ERROR;
    }

    /* 加密随机数 */
    idle_task_process();
    CardCrypto_3DesRun(MODE_ENCRYPTION, DESKey, deData2, rand); //CPU根据随机，秘钥加密数据计算得出加密后的数据

    CARD_CRYPTO_LOG("random number: %#08X %08X", *(uint32_t *)&rand[0], *(uint32_t *)&rand[4]);
    CARD_CRYPTO_LOG("card run 3des: %#08X %08X", *(uint32_t *)&deData1[0], *(uint32_t *)&deData1[4]);
    CARD_CRYPTO_LOG("mcu run 3des : %#08X %08X", *(uint32_t *)&deData2[0], *(uint32_t *)&deData2[4]);

    /* 比较卡片加密值和本地加密值 */
    if ((*(uint32_t *)&deData1 == *(uint32_t *)&deData2) && (*(uint32_t *)&deData1[4] == *(uint32_t *)&deData2[4]))
    {
        *err = 0;
        CARD_CRYPTO_LOG("verify success\r\n");
        return SUCCESS;
    }
    CARD_CRYPTO_LOG("verify failed\r\n");
    return ERROR;
}

/**
  * @brief  添加新卡片
  * @note   生成一个卡片密钥，写入CPU卡
  *         
  * @param  pCardId：卡片ID
  * @param  idLen：卡片ID长度
  *
  * @return SUCCESS/ERROR
  */
ErrorStatus CardCrypto_AddCard(uint8_t *pCardId, uint8_t idLen, uint8_t type)
{
    ErrorStatus status;
    uint8_t DESKey[16];

    if (type != CPU_CARD)
    {
        CARD_CRYPTO_LOG("Card type error\r\n");
        return ERROR;
    }

    /* 选择DF */
    idle_task_process();
    status = FMcos_selectByName((uint8_t *)Default_DF_NAME); //根据名字选择目录
    if (status != SUCCESS)
    {
        idle_task_process();
        status = FMcos_selectByName((uint8_t *)Default_DF_NAME);
        if (status != SUCCESS)
        {
            CARD_CRYPTO_LOG("Select file failed:\"%s\"\r\n", Default_DF_NAME);
            return ERROR;
        }
    }
    CARD_CRYPTO_LOG("Select file succeed:\"%s\"", Default_DF_NAME);

    /* 外部认证--获取卡片文件的写权限
     * 从卡里面获取一个随机数，用Default_Df_ExKey加密，将密文发给卡片，卡片返回验证结果
     */
    idle_task_process();
    status = FMcos_externalAuthenticate(Default_ExKey_Id, (uint8_t *)Default_Df_ExKey, Tdes_Key_Len);
    if (status != SUCCESS)
    {
        CARD_CRYPTO_LOG("External authenticate failed\r\n");
        return ERROR;
    }
    CARD_CRYPTO_LOG("External authenticate succeed");

    /* 计算加密密钥 */
    idle_task_process();
    status = CardCrypto_GetCardKey(pCardId, idLen, DESKey);
    if (status == ERROR)
    {
        return ERROR;
    }

    /* 更新DES加密密钥 */
    idle_task_process();
    status = FMcos_updateKey(DesEncryptKeyType, Default_EncKey_Id, DESKey, 16);
    if (status != SUCCESS)
    {
        CARD_CRYPTO_LOG("Write CARD-DES-KEY failed\r\n");
        return ERROR;
    }
    CARD_CRYPTO_LOG("Write CARD-DES-KEY succeed\r\n");
    return SUCCESS;
}
